package Day15;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

/**
 * 需求说明:
 *  课题：基于TCP协议实现多个聊天室
 *  涉及知识点：
 *   1、IO流(字符缓冲流)
 *   2、多线程 (服务器为多个客户端提供服务)
 *   3、网络通讯 (ServerSocket、Socket)
 *   4、Java容器类 (ArrayList)
 *
 */
public class ChatServer {
    //存放所有的客户端套接字
    private static List<Socket> socketList = new ArrayList<>();

    /**
     * 服务器启动方法
     * @param port 服务器监听的端口
     */
    public static void startupServer(int port) throws IOException {
        ServerSocket server = null;
        server = new ServerSocket(port);
        System.out.println("聊天室已启动...");
        while(true) {  //服务器不能停，一直监听客户端连接请求
            Socket client = server.accept(); //阻塞方法，接收客户端连接请求
            socketList.add(client);
            //获取远程客户端相关信息  IP地址和端口信息
            int remotePort = client.getPort();
            String remoteIP = client.getInetAddress().getHostAddress();
            System.out.println(remoteIP +":" + remotePort + "客户端进入聊天室");
            System.out.println("当前聊天室的总在线人数为：" + socketList.size());
            new Thread(new ServerThreadHandler(socketList,client)).start();
        }
    }


    //内部类实现多线程   每当一个客户端成功与服务器建立连接，开启一个新的线程服务
    private static class ServerThreadHandler implements Runnable {
        private List<Socket> socketList;
        private final Socket socket;

        //带参构造方法
        public ServerThreadHandler(List<Socket> socketList,final Socket socket) {
            this.socketList = socketList;
            this.socket = socket;
        }

        @Override
        public void run() {
            System.out.println("当前线程对象名称为：" + Thread.currentThread().getName() + "为" + this.socket.getInetAddress().getHostAddress() + ":"  + this.socket.getPort()+"服务。。。");
            BufferedReader in = null;
            try{

                while (true) {
                    in = new BufferedReader(
                            new InputStreamReader(
                                    this.socket.getInputStream(), "UTF-8"));

                    //服务器端读取客户端发送过来的数据
                    String msg = in.readLine();

                    //只要有一个客户端发送消息，立刻马上把信息分发给每一个客户端，从而达到群聊功能
                    System.out.println("打印客户端发送过来的信息为：" + msg);
                    dispatch(msg);
                }
            }
            catch (Exception ex) {
                String remoteIP = this.socket.getInetAddress().getHostAddress();
                int port = this.socket.getPort();
                System.out.println(remoteIP + ":" + port + "已离开聊天室");
                this.socketList.remove(this.socket);
                if(this.socket != null && ! this.socket.isClosed()) {
                    try {
                        this.socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("当前聊天室总在线人数为：【" + this.socketList.size() + "】人。");
            }
        }
        //给每一个客户端分发信息
        private void dispatch(String msg) {
            PrintWriter out = null;
            if(socketList == null || socketList.size() == 0) {
                return;
            }
            if(socketList != null && socketList.size() > 0) {
                for (Socket client : socketList) {
                    if(client.equals(socket)) { //自己发的信息，不要再发给自己了，排除自己
                        continue;
                    }
                    try {
                        out = new PrintWriter(client.getOutputStream(), true);
                        out.println(msg);
                    }
                    catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
            }
        }
    }

    //程序入口
    public static void main(String[] args) {
        try {
            startupServer(8080);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
